﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;

namespace UtilZ.Dotnet.WindowsDesktopEx.WPF
{
    /// <summary>
    /// 数值输入控件
    /// </summary>
    public partial class NumberControl
    {
        /// <summary>
        /// 重写OnPreviewMouseDown
        /// </summary>
        /// <param name="e"></param>
        protected override void OnPreviewMouseDown(MouseButtonEventArgs e)
        {
            base.OnPreviewMouseDown(e);

            if (e.Handled)
            {
                return;
            }

            if (this._enablePreviewMouseDown)
            {
                this.Focus();
                e.Handled = true;
            }
        }

        /// <summary>
        /// 重写OnGotFocus
        /// </summary>
        /// <param name="e"></param>
        protected override void OnGotFocus(RoutedEventArgs e)
        {
            base.OnGotFocus(e);

            this.SelectAll();
            this._enablePreviewMouseDown = false;
        }

        /// <summary>
        /// 重写OnLostFocus
        /// </summary>
        /// <param name="e"></param>
        protected override void OnLostFocus(RoutedEventArgs e)
        {
            base.OnLostFocus(e);

            this._enablePreviewMouseDown = true;
            this.CommitValue();
        }






        private static Key[] _numberKeyArr = null;
        private static Key[] _allowInputKeyArr = null;
        private bool _lastPressDownCtrl = false;
        /// <summary>
        /// 移除选中内容
        /// </summary>
        private const Key _REMOVE_SELECTION = Key.Clear;
        /// <summary>
        /// 无
        /// </summary>
        private const Key _NONE = Key.None;
        private Key _textChangedKey = _NONE;

        /// <summary>
        /// 重写OnPreviewKeyDown
        /// </summary>
        /// <param name="e"></param>
        protected override void OnPreviewKeyDown(KeyEventArgs e)
        {
            base.OnPreviewKeyDown(e);

            if (e.Handled)
            {
                //已验证,不再验证
                return;
            }

            if (this._lastPressDownCtrl)
            {
                switch (e.Key)
                {
                    case Key.C:
                        this.CopyCommand_Executed(this, null);
                        break;
                    case Key.V:
                        this.PasteCommand_Executed(this, null);
                        break;
                    default:
                        break;
                }

                this._lastPressDownCtrl = false;
                return;
            }


            switch (e.Key)
            {
                case Key.Tab:
                case Key.Left:
                case Key.Right:
                    return;
                case Key.Back:
                    if (this.SelectionLength > 0)
                    {
                        if (this.SelectionLength == 1 && this.IsNoNumberChar(this.SelectedText[0]))
                        {
                            this.SelectionLength = 0;
                        }
                        else
                        {
                            this._textChangedKey = _REMOVE_SELECTION;
                            int removeStartIndex = this.SelectionStart - 1;
                            int removeLength = this.SelectionLength;
                            while (removeStartIndex >= 0 && this.IsNoNumberChar(this.Text[removeStartIndex]))
                            {
                                removeLength++;
                                removeStartIndex--;
                            }
                            removeStartIndex += 1;
                            this.Text = this.Text.Remove(removeStartIndex, removeLength);
                            this.SelectionStart = removeStartIndex;
                            this._textChangedKey = _NONE;
                            this.FormatEditContent();
                            e.Handled = true;
                            return;
                        }
                    }
                    else
                    {
                        int cursorPreCharIndex = this.SelectionStart - 1;
                        while (cursorPreCharIndex < this.Text.Length &&
                            cursorPreCharIndex >= 0 && this.IsNoNumberChar(this.Text[cursorPreCharIndex]))
                        {
                            cursorPreCharIndex--;
                        }

                        if (cursorPreCharIndex < this.SelectionStart - 1)
                        {
                            this.SelectionStart = cursorPreCharIndex + 1;
                        }

                        this._textChangedKey = e.Key;
                        return;
                    }
                    break;
                case Key.Delete:
                    if (this.SelectionLength > 0)
                    {
                        if (this.SelectionLength == 1 && this.IsNoNumberChar(this.SelectedText[0]))
                        {
                            int selectionStart = this.SelectionStart + 1;
                            if (selectionStart > this.Text.Length)
                            {
                                selectionStart = this.Text.Length - 1;
                            }

                            this.SelectionStart = selectionStart;
                            this.SelectionLength = 0;
                        }
                        else
                        {
                            this._textChangedKey = _REMOVE_SELECTION;
                            int removeStartIndex = this.SelectionStart - 1;
                            int removeLength = this.SelectionLength;
                            while (removeStartIndex >= 0 && this.IsNoNumberChar(this.Text[removeStartIndex]))
                            {
                                removeLength++;
                                removeStartIndex--;
                            }
                            removeStartIndex += 1;
                            this.Text = this.Text.Remove(removeStartIndex, removeLength);
                            this.SelectionStart = removeStartIndex;
                            this._textChangedKey = _NONE;
                            this.FormatEditContent();
                            e.Handled = true;
                            return;
                        }
                    }
                    else
                    {
                        int cursorNextCharIndex = this.SelectionStart;
                        while (cursorNextCharIndex < this.Text.Length &&
                            cursorNextCharIndex >= 0 && this.IsNoNumberChar(this.Text[cursorNextCharIndex]))
                        {
                            cursorNextCharIndex++;
                        }

                        if (cursorNextCharIndex < this.Text.Length && cursorNextCharIndex > this.SelectionStart)
                        {
                            this.SelectionStart = cursorNextCharIndex;
                        }

                        this._textChangedKey = e.Key;
                        return;
                    }
                    break;
                case Key.Enter:
                    this.CommitValue();
                    break;
                case Key.LeftCtrl:
                case Key.RightCtrl:
                    this._lastPressDownCtrl = true;
                    return;
            }

            if (_allowInputKeyArr == null)
            {
                _numberKeyArr = new Key[]
                {
                    Key.NumPad0, Key.NumPad1, Key.NumPad2, Key.NumPad3, Key.NumPad4, Key.NumPad5, Key.NumPad6, Key.NumPad7, Key.NumPad8, Key.NumPad9,  //小键盘数字
                    Key.D0,Key.D1,Key.D2,Key.D3,Key.D4,Key.D5,Key.D6,Key.D7,Key.D8,Key.D9,  //数字
                };
                _allowInputKeyArr = new Key[]
                {
                    Key.NumPad0, Key.NumPad1, Key.NumPad2, Key.NumPad3, Key.NumPad4, Key.NumPad5, Key.NumPad6, Key.NumPad7, Key.NumPad8, Key.NumPad9,  //小键盘数字
                    Key.D0,Key.D1,Key.D2,Key.D3,Key.D4,Key.D5,Key.D6,Key.D7,Key.D8,Key.D9,  //数字
                    Key.OemPeriod,Key.Decimal, //小数点
                    Key.OemMinus, Key.Subtract,  //减号
                    Key.Home,Key.End
                };
            }

            if (!_allowInputKeyArr.Contains(e.Key))
            {
                if (e.Key != Key.Enter)
                {
                    e.Handled = true;
                }
                return;
            }

            if (this.SelectionLength > 0)
            {
                if (_numberKeyArr.Contains(e.Key) && this.SelectionLength == 1 && this.IsNoNumberChar(this.SelectedText[0]))
                {
                    this.SelectionLength = 0;
                    e.Handled = true;
                    return;
                }

                if (this.SelectionLength == this.Text.Length)
                {
                    this.Text = string.Empty;
                }
                else
                {
                    this._textChangedKey = _REMOVE_SELECTION;
                    var selectionStart = this.SelectionStart;
                    this.Text = this.Text.Remove(selectionStart, this.SelectionLength);
                    this.SelectionStart = selectionStart;
                    this._textChangedKey = _NONE;
                }
            }

            this._textChangedKey = e.Key;
        }

        private bool IsNoNumberChar(char ch)
        {
            return ch != '.' && ch != '-' && ch < 48 || ch > 57;
        }


        private void CommitValue()
        {
            if (!this._valueNoComit)
            {
                this.UpdateTextByValue(this.Value);
                return;
            }

            double value;
            string text = this.GetValueText(this.Text);

            if (string.IsNullOrWhiteSpace(text))
            {
                if (this.AllowNaN)
                {
                    value = double.NaN;
                }
                else
                {
                    value = this.Value;
                }
            }
            else
            {
                if (text.EndsWith(_POINT))
                {
                    text = text.Substring(0, text.Length - 1);
                }

                if (double.TryParse(text, out value))
                {
                    if (value - this.Minimum < this._precision)
                    {
                        value = this.Minimum;
                    }
                    else if (value - this.Maximum > this._precision)
                    {
                        value = this.Maximum;
                    }
                }
                else
                {
                    value = this.Value;
                }
            }

            if (!(double.IsNaN(this.Value) || double.IsPositiveInfinity(this.Value) || double.IsNegativeInfinity(this.Value)) &&
                !(double.IsNaN(value) || double.IsPositiveInfinity(value) || double.IsNegativeInfinity(value)) &&
                Math.Abs(this.Value - value) <= this._precision)
            {
                this.UpdateTextByValue(value);
            }
            else
            {
                this.Value = value;
            }

            this._valueNoComit = false;
        }

        private string GetValueText(string srcText)
        {
            if (this.Converter == null)
            {
                return srcText;
            }

            object result = this.Converter.ConvertBack(srcText, null, null, null);
            if (result != null)
            {
                return result.ToString();
            }
            else
            {
                return string.Empty;
            }
        }





        private static string[] _allowInputStrArr = null;
        /// <summary>
        /// 重写OnPreviewTextInput
        /// </summary>
        /// <param name="e"></param>
        protected override void OnPreviewTextInput(TextCompositionEventArgs e)
        {
            base.OnPreviewTextInput(e);

            if (e.Handled)
            {
                //已验证,不再验证
                return;
            }

            if (_allowInputStrArr == null)
            {
                _allowInputStrArr = new string[]
                {
                    "-",".","0","1","2","3","4","5","6","7","8","9"
                };
            }

            if (!_allowInputStrArr.Contains(e.Text))
            {
                //输入了非数字相关的字符
                e.Handled = true;
                return;
            }

            if (this.Maximum >= this._precision)
            {
                if (this.Minimum >= this._precision)
                {
                    //皆为非负数
                    this.OnPreviewTextInput_AllGreaterOrEqualToZero(e);
                }
                else
                {
                    //最大值非负数,最小值负数
                    this.OnPreviewTextInput_MinimumLessThanZero(e);
                }
            }
            else
            {
                //皆为负数
                this.OnPreviewTextInput_AllLessThanZero(e);
            }
        }

        /// <summary>
        /// 皆为负数
        /// </summary>
        /// <param name="e"></param>
        private void OnPreviewTextInput_AllLessThanZero(TextCompositionEventArgs e)
        {
            int decimalPlaces = this.DecimalWidth;
            if (decimalPlaces < _LIMIT && string.Equals(e.Text, _POINT))
            {
                //小数位数为0,输入了小数点
                e.Handled = true;
                return;
            }

            string text = this.GetPreviewTextInputText(e);
            text = this.GetValueText(text);

            if (string.IsNullOrWhiteSpace(text) || string.Equals(text, _SUBTRACT))
            {
                //没有值呀只有减号,不验证
                return;
            }

            if (!text.StartsWith(_SUBTRACT))
            {
                //不以减号开始
                e.Handled = true;
                return;
            }

            if (text.IndexOf(_SUBTRACT) != text.LastIndexOf(_SUBTRACT))
            {
                //输入了多个减号
                e.Handled = true;
                return;
            }

            if (text.StartsWith(_POINT))
            {
                //以小数点开始
                e.Handled = true;
                return;
            }

            if (text.Length >= 2 && text[0] == _ZEROR && text[1] == _ZEROR)
            {
                //起始输入多个0
                e.Handled = true;
                return;
            }

            double value;
            int decimalPointPostion = text.IndexOf(_POINT);
            if (decimalPointPostion > 0)
            {
                if (decimalPointPostion != text.LastIndexOf(_POINT))
                {
                    //多个小数点
                    e.Handled = true;
                    return;
                }

                if (text.EndsWith(_POINT))
                {
                    if (this.SelectionStart == this.Text.Length)
                    {
                        if (!double.TryParse(this.Text, out value))
                        {
                            //无效值
                            e.Handled = true;
                            return;
                        }

                        if (value - this.Minimum <= this._precision)
                        {
                            //整数部分已经为最小值
                            e.Handled = true;
                            return;
                        }
                        else if (value - this.Maximum > this._precision)
                        {
                            //整数部分大于最大值
                            e.Handled = true;
                            return;
                        }
                    }

                    //以小数结尾,其它不验证
                    return;
                }

                if (text.Length - decimalPointPostion - 1 > decimalPlaces)
                {
                    //小数位数超过设定值
                    e.Handled = true;
                    return;
                }
            }

            if (!double.TryParse(text, out value))
            {
                //无效值
                e.Handled = true;
                return;
            }

            if (value - this.Minimum < this._precision)
            {
                //值小于最小值
                e.Handled = true;
                return;
            }
        }

        /// <summary>
        /// 最大值非负数,最小值负数
        /// </summary>
        /// <param name="e"></param>
        private void OnPreviewTextInput_MinimumLessThanZero(TextCompositionEventArgs e)
        {
            int decimalPlaces = this.DecimalWidth;
            if (decimalPlaces < _LIMIT && string.Equals(e.Text, _POINT))
            {
                //小数位数为0,输入了小数点
                return;
            }

            string text = this.GetPreviewTextInputText(e);
            text = this.GetValueText(text);

            if (string.IsNullOrWhiteSpace(text) || string.Equals(text, _SUBTRACT))
            {
                //没有值呀只有减号,不验证
                return;
            }

            if (text.IndexOf(_SUBTRACT) != text.LastIndexOf(_SUBTRACT))
            {
                //输入了多个减号
                e.Handled = true;
                return;
            }

            if (text.StartsWith(_POINT))
            {
                //以小数点开始
                e.Handled = true;
                return;
            }

            if (text.Length >= 2 && text[0] == _ZEROR && text[1] == _ZEROR)
            {
                //起始输入多个0
                e.Handled = true;
                return;
            }

            double value;
            int decimalPointPostion = text.IndexOf(_POINT);
            if (decimalPointPostion > 0)
            {
                if (decimalPointPostion != text.LastIndexOf(_POINT))
                {
                    //多个小数点
                    e.Handled = true;
                    return;
                }

                if (text.EndsWith(_POINT))
                {
                    if (this.SelectionStart == this.Text.Length)
                    {
                        if (!double.TryParse(this.Text, out value))
                        {
                            //无效值
                            e.Handled = true;
                            return;
                        }

                        if (value - this.Maximum >= this._precision)
                        {
                            //整数部分大于最大值
                            e.Handled = true;
                            return;
                        }

                        if (value - this.Minimum <= this._precision)
                        {
                            //整数部分已经为最小值
                            e.Handled = true;
                            return;
                        }
                    }

                    //以小数结尾,其它不验证
                    return;
                }

                if (decimalPlaces >= _LIMIT && text.Length - decimalPointPostion - 1 > decimalPlaces)
                {
                    //小数位数超过设定值
                    e.Handled = true;
                    return;
                }
            }

            if (!double.TryParse(text, out value))
            {
                //无效值
                e.Handled = true;
                return;
            }

            if (value < this._precision)
            {
                if (value - this.Minimum < this._precision)
                {
                    //小于最小值
                    e.Handled = true;
                    return;
                }
            }
            else
            {
                if (value - this.Maximum > this._precision)
                {
                    //大于最大值
                    e.Handled = true;
                    return;
                }
            }
        }

        /// <summary>
        /// 皆为非负数
        /// </summary>
        /// <param name="e"></param>
        private void OnPreviewTextInput_AllGreaterOrEqualToZero(TextCompositionEventArgs e)
        {
            if (string.Equals(e.Text, _SUBTRACT))
            {
                //输入了减号
                e.Handled = true;
                return;
            }

            int decimalWidth = this.DecimalWidth;
            if (decimalWidth < _LIMIT && string.Equals(e.Text, _POINT))
            {
                //小数位数为0,输入了小数点
                e.Handled = true;
                return;
            }

            string text = this.GetPreviewTextInputText(e);
            text = this.GetValueText(text);

            if (string.IsNullOrWhiteSpace(text))
            {
                //没有值,不验证
                return;
            }

            if (text.StartsWith(_POINT))
            {
                //以小数点开始
                e.Handled = true;
                return;
            }

            if (text.Length >= 2 && text[0] == _ZEROR && text[1] == _ZEROR && this.IntegerWidth == 0)
            {
                //起始输入多个0
                e.Handled = true;
                return;
            }

            double value;
            int decimalPointPostion = text.IndexOf(_POINT);
            if (decimalPointPostion > 0)
            {
                if (decimalPointPostion != text.LastIndexOf(_POINT))
                {
                    //多个小数点
                    e.Handled = true;
                    return;
                }

                if (text.EndsWith(_POINT))
                {
                    //以小数结尾,其它不验证
                    return;
                }

                if (text.Contains(_POINT) && this.SelectionStart == this.Text.Length
                    && (text.Length - text.LastIndexOf(_POINT) - 1 >= decimalWidth))
                {
                    if (!double.TryParse(text, out value))
                    {
                        //无效值
                        e.Handled = true;
                        return;
                    }

                    if (value - this.Minimum < this._precision)
                    {
                        //整数部分已经为最小值
                        e.Handled = true;
                        return;
                    }
                    else if (value - this.Maximum >= this._precision)
                    {
                        //整数部分大于最大值
                        e.Handled = true;
                        return;
                    }
                }


                if (decimalWidth > 0 && text.Length - decimalPointPostion - 1 > decimalWidth)
                {
                    //小数位数超过设定值
                    e.Handled = true;
                    return;
                }
            }

            if (!double.TryParse(text, out value))
            {
                //无效值
                e.Handled = true;
                return;
            }

            if (value - this.Maximum > this._precision)
            {
                //大于最大值
                e.Handled = true;
                return;
            }
        }

        private string GetPreviewTextInputText(TextCompositionEventArgs e)
        {
            return this.Text.Insert(this.SelectionStart, e.Text);
        }





        /// <summary>
        /// 重写OnTextChanged
        /// </summary>
        /// <param name="e"></param>
        protected override void OnTextChanged(TextChangedEventArgs e)
        {
            base.OnTextChanged(e);

            if (this._setShowText)
            {
                return;
            }

            this._valueNoComit = true;
            if (this._textChangedKey == _REMOVE_SELECTION || this._textChangedKey == _NONE)
            {
                return;
            }

            this.FormatEditContent();
            this._textChangedKey = _NONE;
        }

        private void FormatEditContent()
        {
            if (this.Converter != null)
            {
                int cursorRightContentLenth = this.Text.Length - this.SelectionStart;
                object obj = this.Converter.ConvertBack(this.Text, null, null, null);
                object result = this.Converter.Convert(obj, null, null, null);
                if (result != null)
                {
                    this.Text = result.ToString();
                    int selectionStart = this.Text.Length - cursorRightContentLenth;
                    if (selectionStart < 0)
                    {
                        selectionStart = 0;
                    }

                    this.SelectionStart = selectionStart;
                }
                else
                {
                    this.Text = string.Empty;
                }
            }
        }
    }
}
